package com.fxu.framework.biz.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.ReflectUtil;
import com.fxu.framework.core.sql.SField;
import com.fxu.framework.core.sql.SFunc;
import lombok.Data;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 业务列表工具类
 * @author fangxu
 * @version 1.5.8
 */
@Component
public final class BizUtil {
	public static final FastDateFormat DATE_FORMAT = FastDateFormat.getInstance("yyyyMMdd");
	public static final FastDateFormat INT_MONTH_FORMAT = FastDateFormat.getInstance("yyyyMM");
	private static final String DOT = ",";

	public static Integer getDateInt(Date date) {
		return (date == null) ? null : Integer.parseInt(DateUtil.format(date, DATE_FORMAT));
	}

	public static Integer getMonthInt(Date date) {
		return (date == null) ? null : Integer.parseInt(DateUtil.format(date, INT_MONTH_FORMAT));
	}

	public static boolean isTrue(Boolean value) {
		return value != null && value;
	}

	public static boolean isFalse(Boolean value) {
		return value == null || !value;
	}

	/**
	 * 拷贝新对象集合且新增加一个对象
	 * @param list 对象集合
	 * @param add 添加对象
	 * @param <T> 对象
	 * @return 新对象集合
	 */
	public static <T> List<T> copyAndPush(List<T> list, T add) {
		if (CollUtil.isEmpty(list)) return CollUtil.toList(add);
		List<T> tmps = new ArrayList<>(list);
		tmps.add(add);
		return tmps;
	}

	// 获取属性并返回Text字段
	public static String toText(List<String> list) {
		if (CollUtil.isEmpty(list)) return null;
		return list.stream().filter(Objects::nonNull).collect(Collectors.joining(DOT));
	}

	// 获取属性并返回Text字段
	public static <T> String toText(List<T> list, SFunc<T, String> func) {
		if (CollUtil.isEmpty(list) || func == null) return null;
		return list.stream().filter(Objects::nonNull).map(func).filter(Objects::nonNull)
				.map(Object::toString).collect(Collectors.joining(DOT));
	}

	// 填充文件URL中文件名称 url?name&size => 前端可以识别出来的字符串
	public static <T> List<T> fillUrl(List<T> list, SFunc<T, String> func, List<SFile> fileList) {
		if (CollUtil.isEmpty(list) || func == null || CollUtil.isEmpty(fileList)) return list;
		@SuppressWarnings("unchecked")
 		Class<T> clazz = (Class<T>)list.get(0).getClass();
		String field = SField.getName(clazz, func);
		Set<String> newUrls = fileList.stream().filter(Objects::nonNull)
				.map(v -> v.getUrl() + "?" + v.getName() + "&" + v.getSize()).collect(Collectors.toSet());
		for (T bean : list) {
			String url = func.apply(bean);
			if (url != null) {
				String newUrl = newUrls.stream().filter(v -> v.startsWith(url)).findFirst().orElse(url);
				ReflectUtil.setFieldValue(bean, field, newUrl);
			}
		}
		return list;
	}

	// 返回列表
	public static <T> List<T> notNull(List<T> list) {
		return CollUtil.isEmpty(list) ? new ArrayList<>() : list;
	}

	// 返回集合
	public static <T, R> Set<R> toSet(List<T> list, SFunc<T, R> func) {
		if (CollUtil.isEmpty(list) || func == null) return new HashSet<>();
		return list.stream().filter(Objects::nonNull).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
	}

	// 返回列表
	public static <T, R> List<R> toList(List<T> list, SFunc<T, R> func) {
		if (CollUtil.isEmpty(list) || func == null) return new ArrayList<>();
		return list.stream().filter(Objects::nonNull).map(func).filter(Objects::nonNull).collect(Collectors.toList());
	}

	// 返货过滤函数且不对原列表改变
	public static <T> List<T> filter(List<T> list, Predicate<? super T> predicate) {
		if (CollUtil.isEmpty(list) || predicate == null) return list;
		return list.stream().filter(Objects::nonNull).filter(predicate).collect(Collectors.toList());
	}

	// 获得对象属性值, 找不到返回null
	public static <T, R> R getValue(T bean, SFunc<T, R> func) {
		return getValue(bean, func, null);
	}

	// 获得对象属性值, 找不到返回defValue
	public static <T, R> R getValue(T bean, SFunc<T, R> func, R defValue) {
		if (bean == null || func == null) return defValue;
		R value = func.apply(bean);
		return null == value ? defValue : value;
	}

	public static <T> BigDecimal getDecimal(T bean, SFunc<T, BigDecimal> func, int scale, BigDecimal defValue) {
		BigDecimal value = getValue(bean, func, defValue);
		return null == value ? null : value.setScale(scale, RoundingMode.DOWN);
	}

	// 找到对象属性, 找不到返回false，否则返回true
	public static <T> boolean exists(List<T> list, Filter<T> filter) {
		if (CollUtil.isEmpty(list) || filter == null) return false;
		return CollUtil.findOne(list, filter) != null;
	}

	// 找到对象属性, 找不到返回defValue
	public static <T, R> R findValue(List<T> list, Filter<T> filter, SFunc<T, R> func, R defValue) {
		if (CollUtil.isEmpty(list) || filter == null || func == null) return defValue;
		T bean = CollUtil.findOne(list, filter);
		return getValue(bean, func, defValue);
	}

	// 找到对象属性, 找不到返回null
	public static <T, R> R findValue(List<T> list, Filter<T> filter, SFunc<T, R> func) {
		return findValue(list, filter, func, null);
	}

	// 累加器
	public static <T, R> R reduce(List<T> list, SFunc<T, R> func, R identity, BinaryOperator<R> accumulator) {
		if (CollUtil.isEmpty(list) || func == null) return null;
		return list.stream().filter(Objects::nonNull).map(func).filter(Objects::nonNull).reduce(identity, accumulator);
	}

	public static <T> BigDecimal reduceDecimal(List<T> list, SFunc<T, BigDecimal> func, BigDecimal defaultVal) {
		if (CollUtil.isEmpty(list) || func == null) return defaultVal;
		return reduce(list, func, BigDecimal.ZERO, BigDecimal::add);
	}

	public static <T> BigDecimal reduceDecimalZero(List<T> list, SFunc<T, BigDecimal> func) {
		return reduceDecimal(list, func, BigDecimal.ZERO);
	}

	public static <T> BigDecimal reduceDecimalNull(List<T> list, SFunc<T, BigDecimal> func) {
		return reduceDecimal(list, func, null);
	}

	public static <T> Integer reduceInteger(List<T> list, SFunc<T, Integer> func, Integer defaultVal) {
		if (CollUtil.isEmpty(list) || func == null) return defaultVal;
		return reduce(list, func, 0, Integer::sum);
	}

	public static <T> Integer reduceIntegerZero(List<T> list, SFunc<T, Integer> func) {
		return reduceInteger(list, func, 0);
	}

	public static <T> Integer reduceIntegerNull(List<T> list, SFunc<T, Integer> func) {
		return reduceInteger(list, func, null);
	}

	public static <T> Long reduceLong(List<T> list, SFunc<T, Long> func, Long defaultVal) {
		if (CollUtil.isEmpty(list) || func == null) return defaultVal;
		return reduce(list, func, 0L, Long::sum);
	}

	public static <T> Long reduceLongZero(List<T> list, SFunc<T, Long> func) {
		return reduceLong(list, func, 0L);
	}

	public static <T> Long reduceLongNull(List<T> list, SFunc<T, Long> func) {
		return reduceLong(list, func, null);
	}

	// 找到值大于0
	public static <T> boolean anyAboveZero(List<T> list, SFunc<T, BigDecimal> func) {
		if (CollUtil.isEmpty(list) || func == null) return false;
		return list.stream().anyMatch(v -> func.apply(v).compareTo(BigDecimal.ZERO) > 0);
	}

	@Data
	public static class SFile {
		private Long id;
		private String url;
		private String name;
		private Long size;
	}
}
